﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using Microsoft.Web.Media.SmoothStreaming;
//using Microsoft.SilverlightMediaFramework.Core;
//using Microsoft.SilverlightMediaFramework.Plugins.Primitives;
using System.Collections.ObjectModel;
using LiveStream.Caching;
using System.Windows.Threading;

namespace LiveStream
{
	public partial class PlaybackControls : UserControl
	{
		NativePlayer _nativePlayer;

		const int SEEK_MILLISECONDS = 250;
        const int SEEK_BIG_MILLISECONDS = 1000;
        bool _isPreviewing = false;
        TimeSpan _beforePreviewTime=TimeSpan.MinValue;
        DispatcherTimer _previewTimer = new DispatcherTimer();
        TimeSpan _bookmarkPosition = TimeSpan.MinValue;
        TimeSpan _lastKnownGoodPosition = TimeSpan.Zero;
        bool _resetting = false;

		public PlaybackControls(NativePlayer nativePlayer)
		{
			InitializeComponent();
			_nativePlayer = nativePlayer;
			this.Loaded += new RoutedEventHandler(OnLoaded);
            _previewTimer.Tick += new EventHandler(previewTimer_Tick);
            this.KeyUp += new KeyEventHandler(PlaybackControls_KeyUp);
		}

		private void SourceSelectionChanged(object sender, SelectionChangedEventArgs e)
		{
            VideoSource video = (VideoSource) SourceSelectionCombo.SelectedItem;
            
            _bookmarkPosition = TimeSpan.MinValue;
            GoToBookmark.IsEnabled = false;
            _lastKnownGoodPosition = TimeSpan.Zero;

			_nativePlayer.SmoothStreamingSource = video.Source;
		}

		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
		}

		private void OnLoaded(object sender, RoutedEventArgs args)
		{
            slider1.Initialize(_nativePlayer);

            _nativePlayer.DownloadTrackChanged += new EventHandler<TrackChangedEventArgs>(
                    (s, e) =>
                    {
                        double downloadMbit = _nativePlayer.VideoDownloadTrack.Bitrate / 1000000.0;
                        CurrentDownloadBitrate.Content = downloadMbit.ToString("0.#") + "Mbit";
                    }
                );

            _nativePlayer.PlaybackTrackChanged += new EventHandler<TrackChangedEventArgs>(
                    (s, e) =>
                    {
                        double playbackMbit = _nativePlayer.VideoPlaybackTrack.Bitrate / 1000000.0;
                        CurrentPlaybackBitrate.Content = playbackMbit.ToString("0.#") + "Mbit";
                    }
                );

			_nativePlayer.EndPositionChanged += new EventHandler<EventArgs<TimeSpan>>(
					(s, e) =>
					{
						EndTime.Content = e.Value.ToString(@"hh\:mm\:ss");
					}
				);

			_nativePlayer.PositionChanged += new EventHandler<EventArgs<TimeSpan>>(
					(s, e) =>
					{
						CurrentTime.Content = e.Value.ToString(@"hh\:mm\:ss");

                        //XYZZY Put this somewhere more relevant?
                        DroppedFrames.Content = _nativePlayer.DroppedFramesPerSecond.ToString()+"/"+_nativePlayer.RenderedFramesPerSecond.ToString();

                        if (_nativePlayer.CurrentState == SmoothStreamingMediaElementState.Playing || _nativePlayer.CurrentState == SmoothStreamingMediaElementState.Paused)
                        {
                            if(_nativePlayer.Position!=TimeSpan.Zero)       //XYZZY not quite right. Needed because the position update timer might fire while we're resetting
                                _lastKnownGoodPosition = _nativePlayer.Position;
                        }
					}
				);

            _nativePlayer.ManifestReady += new EventHandler<EventArgs>(
                    (s, e) =>
                    {
                        foreach (SegmentInfo segment in _nativePlayer.ManifestInfo.Segments)
                        {
                            foreach (StreamInfo stream in segment.AvailableStreams)
                            {
                                if (LowBitrateOnly.IsChecked.Value)
                                {
                                    //Use only the minimum-bitrate track
                                    stream.SelectTracks(
                                        (from track in stream.AvailableTracks
                                         orderby track.Bitrate
                                         select track).Take(1).ToList()
                                    , false);
                                }
                                else
                                    stream.SelectTracks(stream.AvailableTracks, false);
                            }
                        }
                    }
                );


			_nativePlayer.SeekCompleted += new EventHandler<SeekCompletedEventArgs>(nativePlayer_SeekCompleted);

			_nativePlayer.LiveEventCompleted += new EventHandler(nativePlayer_LiveEventCompleted);
			_nativePlayer.MediaEnded += new RoutedEventHandler(nativePlayer_MediaEnded);
			_nativePlayer.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>(nativePlayer_MediaFailed);
            _nativePlayer.CurrentStateChanged += new RoutedEventHandler(_nativePlayer_CurrentStateChanged);
		}

        void _nativePlayer_CurrentStateChanged(object sender, RoutedEventArgs e)
        {
            switch (_nativePlayer.CurrentState)
            {
                case SmoothStreamingMediaElementState.Paused:
                case SmoothStreamingMediaElementState.Stopped:
                    PlayButton.IsEnabled = true;
                    PlayButton.Content = "Play";
                    Preview.IsEnabled = true;
                    SetBookmark.IsEnabled = true;
                    if (_bookmarkPosition != TimeSpan.MinValue)
                        GoToBookmark.IsEnabled = true;
                    else
                        GoToBookmark.IsEnabled = false;
                    GoLive.IsEnabled = true;

                    if (_resetting)
                    {
                        //If we're in the process of being reset, go to the last good position
                        _nativePlayer.Position = _lastKnownGoodPosition;
                        _resetting = false;
                    }

                    break;
                case SmoothStreamingMediaElementState.Playing:
                    PlayButton.IsEnabled = true;
                    PlayButton.Content = "Pause";
                    if (_isPreviewing)
                        Preview.IsEnabled = true;
                    else
                        Preview.IsEnabled = false;
                    SetBookmark.IsEnabled = true;
                    if (_bookmarkPosition != TimeSpan.MinValue)
                        GoToBookmark.IsEnabled = true;
                    else
                        GoToBookmark.IsEnabled = false;
                    GoLive.IsEnabled = true;
                    break;
                default:
                    PlayButton.IsEnabled = false;
                    PlayButton.Content = "Play";
                    Preview.IsEnabled = false;
                    SetBookmark.IsEnabled = false;
                    GoToBookmark.IsEnabled = false;
                    GoLive.IsEnabled = false;
                    break;
            }
        }

		void nativePlayer_MediaFailed(object sender, ExceptionRoutedEventArgs e)
		{
			ShowMessage(string.Format("Media Failed: {0}", e.ErrorException.ToString()));
		}

		void nativePlayer_MediaEnded(object sender, RoutedEventArgs e)
		{
			ShowMessage("Media Ended");
		}

		void nativePlayer_LiveEventCompleted(object sender, EventArgs e)
		{
			ShowMessage("Live Event Complete");
		}

		void nativePlayer_SeekCompleted(object sender, SeekCompletedEventArgs e)
		{
			//var message = string.Format("Event Position: {0}\r\nCurrent Position: {1}", e.ActualSeekPosition, nativePlayer.Position);
			//MessageBox.Show(message);
		}


		private void SeekBackwardButton_Click(object sender, RoutedEventArgs e)
		{
			slider1.Value -= SEEK_MILLISECONDS;
		}

		private void SeekForwardButton_Click(object sender, RoutedEventArgs e)
		{
			slider1.Value += SEEK_MILLISECONDS;
		}

		private void PlayButton_Click(object sender, RoutedEventArgs e)
		{
            TogglePlay();
		}

        private void TogglePlay()
        {
            if (SourceSelectionCombo.SelectedValue == null)
                return;

            if (_nativePlayer.CurrentState == SmoothStreamingMediaElementState.Playing)
                _nativePlayer.Pause();
            else
                _nativePlayer.Play();
        }

		private void ShowMessage(string message)
		{
			Deployment.Current.Dispatcher.BeginInvoke(() =>
			{
				MessageContainer.Visibility = System.Windows.Visibility.Visible;
				Message.Content = message;

				var timer = new DispatcherTimer();
				timer.Interval = TimeSpan.FromSeconds(10);
				timer.Tick += ((s, e) =>
				{
					HideMessage();
					timer.Stop();
				});
				timer.Start();
			});
		}

		private void HideMessage()
		{
			Deployment.Current.Dispatcher.BeginInvoke(() =>
			{
				MessageContainer.Visibility = System.Windows.Visibility.Collapsed;
				Message.Content = "";
			});
		}

        private void Fullscreen_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Host.Content.IsFullScreen = true;
        }

        private void Preview_Click(object sender, RoutedEventArgs e)
        {
            if (_isPreviewing)
                EndPreview();
            else
                BeginPreview();
        }

        void BeginPreview()
        {
            _isPreviewing = true;
            Preview.Content = "End Preview";
            _beforePreviewTime = _nativePlayer.Position;
            _nativePlayer.Play();
            _previewTimer.Interval = TimeSpan.FromSeconds(30);
            _previewTimer.Start();
        }

        void EndPreview()
        {
            _previewTimer.Stop();
            Preview.Content = "Preview";
            _nativePlayer.Pause();
            _nativePlayer.Position = _beforePreviewTime;
            _isPreviewing = false;
        }

        void previewTimer_Tick(object sender, EventArgs e)
        {
            EndPreview();
        }

        private void GoLive_Click(object sender, RoutedEventArgs e)
        {
            _nativePlayer.Play();
            _nativePlayer.StartSeekToLive();
        }

        private void SetBookmark_Click(object sender, RoutedEventArgs e)
        {
            _bookmarkPosition = _nativePlayer.Position;
            GoToBookmark.IsEnabled = true;
        }

        private void GoToBookmark_Click(object sender, RoutedEventArgs e)
        {
            if (_bookmarkPosition != TimeSpan.MinValue)
                _nativePlayer.Position = _bookmarkPosition;
        }

        private void Reset_Click(object sender, RoutedEventArgs e)
        {
            ResetVideo(false);
        }

        private void ResetVideo(bool trust_current_position)
        {
            if (SourceSelectionCombo.SelectedItem == null)
                return;

            if (trust_current_position)
                _lastKnownGoodPosition = _nativePlayer.Position;

            VideoSource video = (VideoSource)SourceSelectionCombo.SelectedItem;

            //Select a different source
            _nativePlayer.SmoothStreamingSource = ((VideoSource)SourceSelectionCombo.Items.Last()).Source;  //XYZZY is there a better way to "reset" playback?

            _resetting = true;  //When the state changes to stop, set the position
            _nativePlayer.SmoothStreamingSource = video.Source;
        }

        private void SeekBackwardBigButton_Click(object sender, RoutedEventArgs e)
        {
            slider1.Value -= SEEK_BIG_MILLISECONDS;
        }

        private void SeekForwardBigButton_Click(object sender, RoutedEventArgs e)
        {
            slider1.Value += SEEK_BIG_MILLISECONDS;
        }

        private void LowBitrateOnly_Checked(object sender, RoutedEventArgs e)
        {
            ResetVideo(true);
        }

        private void LowBitrateOnly_Unchecked(object sender, RoutedEventArgs e)
        {
            ResetVideo(true);
        }

        void PlaybackControls_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Space)
                TogglePlay();
        }
	}
}
